package com.oa.system.service;

import java.util.HashSet;
import java.util.Set;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.oa.system.dao.AccountDao;
import com.oa.system.dao.UserInfoDao;
import com.oa.system.entity.UserAccount;
import com.oa.system.entity.UserInfo;
import com.oa.user.dto.UserInfoDto;
import com.oa.util.SessionUtil;

@Service
@Transactional
public class SystemServiceImpl implements SystemService {
	@Resource
	private AccountDao accountDao;
	@Resource
	private UserInfoDao userInfoDao;
	@Resource
	private PasswordEncoder passwordEncoder;

	@Resource
	private HttpServletRequest request;
	@Resource
	private HttpServletResponse response;
	@Resource
	private HttpSession session;

	@Override
	public UserInfoDto login(UserAccount userAccount, boolean rememberMe) {
		UserAccount account = accountDao.findByUsername(userAccount.getUsername());

		if (account != null && passwordEncoder.matches(userAccount.getPassword(), account.getPassword())) {
			UserInfo userInfo = auth(account);
			// 保存用户帐号和加密的密码到Cookie,设置过期时间为24小时
			if (rememberMe) {
				Cookie un = new Cookie("username", account.getUsername());
				un.setMaxAge(60 * 60 * 24);
				response.addCookie(un);
				Cookie pw = new Cookie("password", passwordEncoder.encode(account.getPassword()));
				pw.setMaxAge(60 * 60 * 24);
				response.addCookie(pw);
			}

			return UserInfoDto.toUserInfoDto(userInfo);
		}

		return null;
	}

	@Override
	public void register(UserAccount userAccount, UserInfo userInfo) {
		userAccount.setPassword(passwordEncoder.encode(userAccount.getPassword()));
		UserAccount account = accountDao.save(userAccount);
		userInfo.setId(account.getId());
		userInfoDao.save(userInfo);
	}

	@Override
	public void logout() {
		SessionUtil.removeAttribute(session);
		Cookie[] cookies = request.getCookies();

		// 清除Cookie
		for (int i = 0; i < cookies.length; i++) {
			Cookie cookie = cookies[i];

			if ("username".equals(cookie.getName())) {
				cookie.setMaxAge(0);
				response.addCookie(cookie);
			}

			if ("password".equals(cookie.getName())) {
				cookie.setMaxAge(0);
				response.addCookie(cookie);
			}
		}
	}

	@Override
	public boolean checkRememberMe() {
		Cookie[] cookies = request.getCookies();
		Cookie un = null;
		Cookie pw = null;

		// 从Cookie中找到用户帐号和密码
		for (int i = 0; i < cookies.length; i++) {
			Cookie cookie = cookies[i];

			if ("username".equals(cookie.getName())) {
				un = cookie;
			}

			if ("password".equals(cookie.getName())) {
				pw = cookie;
			}
		}

		// 验证用户帐号和密码
		if (un != null && pw != null) {
			String username = un.getValue();
			String password = pw.getValue();

			UserAccount account = accountDao.findByUsername(username);

			if (passwordEncoder.matches(account.getPassword(), password)) {
				auth(account);
			}

			return true;
		}

		return false;
	}

	private UserInfo auth(UserAccount account) {
		UserInfo userInfo = userInfoDao.findOne(account.getId());

		SessionUtil.setUserName(session, account.getUsername());
		SessionUtil.setUserId(session, userInfo.getId());
		SessionUtil.setName(session, userInfo.getFullname());
		SessionUtil.setUserInfo(session, userInfo);

		// 用户权限
		Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
		if (userInfo.getRole() != null) {
			for (GrantedAuthority grantedAuthority : userInfo.getRole().getGroup()) {
				grantedAuthorities.add(grantedAuthority);
			}
		}

		// 保存认证的信息到SecurityContext中
		SecurityContext securityContext = SecurityContextHolder.getContext();
		UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(account,
				account.getPassword(), grantedAuthorities);

		authenticationToken.setDetails(request);
		securityContext.setAuthentication(authenticationToken);
		SecurityContextHolder.setContext(securityContext);

		return userInfo;
	}

}
